package com.xyq.judge.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xyq.api.domain.QuestionExeResult;
import com.xyq.api.domain.dto.JudgeSubmitDTO;
import com.xyq.api.domain.vo.UserQuestionResultVO;
import com.xyq.common.core.constants.Constants;
import com.xyq.common.core.constants.JudgeConstants;
import com.xyq.common.core.enums.CodeRunStatus;
import com.xyq.judge.domain.SandBoxExecuteResult;
import com.xyq.judge.domain.UserSubmit;
import com.xyq.judge.mapper.UserSubmitMapper;
import com.xyq.judge.service.JudgeService;
import com.xyq.judge.service.SandboxPoolService;
import com.xyq.judge.service.SandboxService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class JudgeServiceImpl implements JudgeService {

    // 沙箱Service做执行代码的逻辑, 而 JudgeService 是完成判题题目的逻辑
    @Autowired
    private SandboxService sandboxService ;

    // 使用容器池优化后的代码沙箱service
    @Autowired
    private SandboxPoolService sandboxPoolService ;

    @Autowired
    private UserSubmitMapper userSubmitMapper ;

    @Override
    public UserQuestionResultVO doJudgeJavaCode(JudgeSubmitDTO judgeSubmitDTO) {
        // 目前需要 代码 + 输入
        // 需要返回 代码的执行结果 , 异常信息, 占用内存 , 消耗时间
       SandBoxExecuteResult sandBoxExecuteResult =
               sandboxPoolService.exeJavaCode( judgeSubmitDTO.getUserId(), judgeSubmitDTO.getUserCode() , judgeSubmitDTO.getInputList());
       // 对执行的结果判断
        UserQuestionResultVO userQuestionResultVO = new UserQuestionResultVO() ;
        // 1. 只有代码运行成功才往下 对比
        if(sandBoxExecuteResult != null && sandBoxExecuteResult.getRunStatus().equals(CodeRunStatus.SUCCEED)){
           // 2. 如果代码执行成功, 对比结果 , 时间限制 , 空间限制

            checkSandBoxExecuteResult(judgeSubmitDTO, userQuestionResultVO, sandBoxExecuteResult);
        }else{
        // 如果运行结果不正确,返回错误原因
            // 代码不通过
            userQuestionResultVO.setPass(Constants.FALSE);
            if(sandBoxExecuteResult != null){
                userQuestionResultVO.setExeMessage(sandBoxExecuteResult.getExeMessage());
            }else{
              userQuestionResultVO.setExeMessage(CodeRunStatus.UNKNOWN_FAILED.getMsg());
            }
            // 成绩 为0
            userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
        }
        // 存储用户提交的代码结果到数据库
        saveUserSubmit(judgeSubmitDTO, userQuestionResultVO);
        // 返回结果
        return userQuestionResultVO;
    }
      // 对比 实际输出结果 , 预期输出结果 , 时间限制和空间限制
    private  UserQuestionResultVO checkSandBoxExecuteResult(JudgeSubmitDTO judgeSubmitDTO,
                                                            UserQuestionResultVO userQuestionResultVO,
                                                            SandBoxExecuteResult sandBoxExecuteResult) {
        // 代码书输出结果 和 预期输出结果对比

        userQuestionResultVO.setPass(Constants.FALSE);
        List<String> outputList = judgeSubmitDTO.getOutputList();
        List<String> expectOutpulList =   sandBoxExecuteResult.getOutputList();
        if(outputList.size() != expectOutpulList.size()){
            userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
            userQuestionResultVO.setExeMessage(JudgeConstants.ERROR_ANSWER);
            return  userQuestionResultVO;
        }
          // 一个个对比
            // 预期结果 和 实际输出 和 输入 的list
            List<QuestionExeResult> questionExeResultList = new ArrayList<>();
            boolean pass = resultCompare(judgeSubmitDTO, outputList, expectOutpulList, questionExeResultList);
            // 预期结果和实际结果不对
            if(!pass){
                userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
                userQuestionResultVO.setExeMessage(JudgeConstants.ERROR_ANSWER);
                 userQuestionResultVO.setQuestionExeResultList(questionExeResultList);
                return userQuestionResultVO;
            }
            // 对比时间限制和 空间限制
            if(sandBoxExecuteResult.getUserMemory() > judgeSubmitDTO.getSpaceLimit()){
                userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
                userQuestionResultVO.setExeMessage(JudgeConstants.OUT_OF_MEMORY);
                return userQuestionResultVO;
            }
            if(sandBoxExecuteResult.getUserTime() > judgeSubmitDTO.getTimeLimit()){
                userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
                userQuestionResultVO.setExeMessage(JudgeConstants.OUT_OF_TIME);
                return userQuestionResultVO;
            }

            // 所有结果都正确
            userQuestionResultVO.setPass(Constants.TRUE);
            // 成绩= 难度 * 默认分数 : 简单: 1 * 10 , 中等: 2 * 10
            int score = JudgeConstants.DEFAULT_SCORE * judgeSubmitDTO.getDifficulty();
            userQuestionResultVO.setScore(score);
             userQuestionResultVO.setQuestionExeResultList(questionExeResultList);
        return userQuestionResultVO ;
    }

  // 判断实际输出 和 预期输出的结果是否正确
    private static boolean resultCompare(JudgeSubmitDTO judgeSubmitDTO, List<String> outputList,
                                         List<String> expectOutpulList,
                                         List<QuestionExeResult> questionExeResultList) {
        boolean pass = true ;
        for(int i = 0; i < outputList.size() ; i ++){
            QuestionExeResult questionExeResult = new QuestionExeResult() ;
            String input = judgeSubmitDTO.getInputList().get(i);
            String output = outputList.get(i);
            String expectOutput = expectOutpulList.get(i);
            questionExeResult.setInput(input);
            questionExeResult.setOutput(output);
            questionExeResult.setExeOutput(expectOutput);
            questionExeResultList.add(questionExeResult);
            if(!output.equals(expectOutput)){
                pass = false ;
                break ;
            }
        }
        return pass;
    }

    private void saveUserSubmit(JudgeSubmitDTO judgeSubmitDTO, UserQuestionResultVO userQuestionResultVO) {
        UserSubmit userSubmit = new UserSubmit();
        userSubmit.setQuestionId(judgeSubmitDTO.getQuestionId());
        userSubmit.setUserId(judgeSubmitDTO.getUserId());
        userSubmit.setExamId(judgeSubmitDTO.getExamId());
        userSubmit.setProgramType(judgeSubmitDTO.getProgramType());
        userSubmit.setPass(userQuestionResultVO.getPass());
        userSubmit.setUserCode(judgeSubmitDTO.getUserCode());
        userSubmit.setScore(userQuestionResultVO.getScore());
        userSubmit.setExeMessage(userQuestionResultVO.getExeMessage());
        userSubmit.setCreateBy(judgeSubmitDTO.getUserId());
        userSubmit.setUpdateBy(judgeSubmitDTO.getUserId());

        // 用户代码的 用例运行结果
        userSubmit.setCaseJudgeRes(JSONUtil.toJsonStr(userQuestionResultVO.getQuestionExeResultList()));

        // 先判断库里是否已经有记录了 , 为了保证记录里只保存 最新的一次提交
        // 不需要保存那么多分, 只需要保存用户最后一次 提交代码的数据
        // 先删除最后上次提交的记录
        userSubmitMapper.delete(new LambdaQueryWrapper<UserSubmit>()
                .eq(UserSubmit::getUserId, judgeSubmitDTO.getUserId())
                .eq(UserSubmit::getQuestionId, judgeSubmitDTO.getQuestionId())
                .isNull(judgeSubmitDTO.getExamId()==null , UserSubmit::getExamId)
                .eq(judgeSubmitDTO.getExamId()!=null , UserSubmit::getExamId , judgeSubmitDTO.getExamId()));
        if(userSubmit.getExeMessage()!=null &&  userSubmit.getExeMessage().length() > 600){
            userSubmit.setExeMessage(userSubmit.getExeMessage().substring(0 , 500) + "...");
        }
        userSubmitMapper.insert(userSubmit);
    }
}
